#pragma once
#include <Windows.h>
#include <esent.h>
#include <string>
#include <filesystem>
#include <vector>
#include <type_traits>
#include <chrono>

namespace ese
{
	template <class T>
	inline JET_ERR set_param(JET_INSTANCE inst, JET_SESID ses, unsigned long paramId, const T paramValue)
	{
		JET_API_PTR param = paramValue;
		return ::JetSetSystemParameter(&inst, 0, paramId, param, 0);
	}
	template <class T>
	inline JET_ERR get_param(JET_INSTANCE inst, JET_SESID ses, unsigned long paramId, T& paramValue)
	{
		JET_API_PTR param = paramValue;
		JET_ERR lastError = ::JetGetSystemParameter(inst, ses, paramId, &param, 0, 0);
		paramValue = param;
		return lastError;
	}
	inline JET_ERR get_param(JET_INSTANCE inst, JET_SESID ses, unsigned long paramId, std::string &s)
	{
		s = "";
		char path[MAX_PATH];
		JET_ERR lastError = ::JetGetSystemParameterA(inst, ses, paramId, 0, path, MAX_PATH);
		s = path;
		return lastError;
	}
	inline JET_ERR set_param(JET_INSTANCE inst, JET_SESID ses, unsigned long paramId, const std::string &s)
	{
		return ::JetSetSystemParameterA(&inst, ses, paramId, 0, s.c_str());
	}

	inline std::string error(const JET_ERR ec)
	{
		char cs[512];
		JET_API_PTR eCode = ec;
		JET_ERR jErr = ::JetGetSystemParameterA(0, 0, JET_paramErrorToString, &eCode, cs, sizeof(cs));
		return std::string(cs);
	}

	//
	// returns the path to the current application
	inline std::tr2::sys::path exe_path()
	{
		char appName[1024];
		if (::GetModuleFileNameA(nullptr, appName, 1024) < 1)
		{
			return std::tr2::sys::path();
		}// if

		return std::tr2::sys::path(appName);
	}

	class IndexKey
	{
	public:
		IndexKey(const char* cs) : m_data(cs, cs + ::strlen(cs)) { m_data.push_back(0);  m_data.push_back(0); }
		IndexKey& operator <<(const char c) { m_data.push_back(c); return *this; }
		IndexKey& operator <<(const std::string &s) { m_data.insert(m_data.end(), s.begin(), s.end()); return *this; }
		IndexKey& operator <<(const char *cs) { m_data.insert(m_data.end(), cs, cs + ::strlen(cs)); return *this; }
		char *data() { return &m_data[0]; }
		const size_t size() const { return m_data.size(); }
		void clear(){ m_data.clear(); }
	private:
		std::vector<char> m_data;
	};
}